#include "handy/handy/handy.h"
#include <algorithm>
#include <list>
#include <stdio.h>
#include <string>
#include <stdint.h>
#include <arpa/inet.h>
#include <sstream>
#include "common.h"
#include "xudp.pb.h"
using namespace std;
using namespace handy;

unsigned int g_id = 0;

std::list<std::shared_ptr<xmsg> > g_unack_msg;
string g_content;
int g_una = 0;

shared_ptr<xmsg> gen_msg() {
	shared_ptr<xmsg> msg = make_shared<xmsg>();
	msg->set_id(g_id++);
	msg->set_buf(g_content.c_str(), MSG_SIZE);
	return msg;
}



int get_content(char* b, int len) {
	xpackage p;
	p.set_cmd(CMD_DATA);
	stringstream ss;

	int content_len = p.ByteSize();
	for (auto itr = g_unack_msg.begin(); itr != g_unack_msg.end();) {
		content_len += (*itr)->ByteSize();
		if (itr->get()->id() >= g_una && content_len < len) {
			ss << itr->get()->id() << "_";
			xmsg* m = p.add_msg();
			*m = *(*itr);
			itr++;
		}
		else {
			break;
		}
	}
	info("id:%d, una:%d, msg:%s", g_id, g_una, ss.str().c_str()); 
	bool suc = p.SerializeToArray(b, len);
	if (!suc) {
		fatal("serialize failed");
		return -1;
	}
	return p.ByteSize();
}

int main() {
	g_content = random_string(500);

	setloglevel("INFO");
  	setlogfile("test_client_full_udp");
	EventBase base;
	Signal::signal(SIGINT, [&] { base.exit(); });
	UdpConnPtr con = UdpConn::createConnection(&base, SERVER_IP, SERVER_PORT);

	exitif(!con, "start udp conn failed");

	con->onMsg([](const UdpConnPtr& p, Buffer buf) {
//		info("udp recved %lu bytes", buf.size());
		xpackage package;
		bool suc = package.ParseFromArray(buf.data(), buf.size());
		if (!suc) {
			warn("decode failed");
			return;
		}
		if (package.cmd() == CMD_ACK) {
			if (g_una < package.una()) {
				info("local:%d ,una:%d", g_una, package.una());
				g_una = package.una();
				for (auto m = g_unack_msg.begin(); m != g_unack_msg.end(); ) {
					if (m->get()->id() < g_una) {
						g_unack_msg.erase(m++);
					}
					else {
						break;
					}
				}
			}
		}
	});

	base.runAfter(0, [&]() {
		shared_ptr<xmsg> msg = gen_msg();
		info("id:%d,time:%ld",msg->id(), util::timeMilli());
		g_unack_msg.push_back(msg);

		char b[500] = {};
		int l = get_content(b, sizeof(b));
		if (l > 0) {
			con->send(b,l);
		}
		if(g_id >MAX_MSG_ID){
			base.exit();
		}
	}, MSG_INTERVAL);

	base.loop();
}
